//
//  BLGCDTimer.swift
//  BLNetworking
//
//  Created by dg on 2023/11/3.
//
// 注意事项：
// 1.dispatch_suspend 和 dispatch_resume 应该是成对出现的
// 2.dispatch_suspend 状态下无法释放 初始状态(未调用dispatch_resume)、挂起状态，都不能直接调用dispatch_source_cancel(timer)
// 3.循环引用的问题

import UIKit

private enum TimerStatus: Int {
    case none = 0, suspend, resume
}

@objc public class BLGCDTimer: NSObject {

    private var time_status = TimerStatus.none
    private var repeating: DispatchTimeInterval = .never
    private var leeway: DispatchTimeInterval = .nanoseconds(0)
    private var workQueue: DispatchQueue! = nil
    private var deadline: DispatchTime = DispatchTime.now()
    private var handler: ()->Void
    private var timer: DispatchSourceTimer? = nil
    
    public init(with queue: DispatchQueue, repeating: DispatchTimeInterval, deadline: DispatchTime = DispatchTime.now(), leeway: DispatchTimeInterval = .nanoseconds(0), handler: @escaping ()->Void) {
        self.workQueue = queue;
        self.repeating = repeating
        self.leeway = leeway
        self.deadline = deadline
        self.handler = handler
        super.init()
        createTimer()
    }
    
    // repeating 时间单位为秒， repeating == 0 永不重复
    @objc public init(with queue: DispatchQueue, repeating: Int, handler: @escaping ()->Void) {
        self.repeating = repeating == 0 ? .never : .seconds(repeating)
        workQueue = queue
        self.handler = handler
        super.init()
        createTimer()
    }
    
    deinit {
        switch time_status {
        case .suspend:
            close()
        case .resume:
            close()
        case .none:
            return
        }
    }
}

@objc public extension BLGCDTimer {
    // 运行
    func run() {
        guard let t = timer else {
            return
        }
        
        switch time_status {
        case .suspend:
            t.resume()
        case .resume:
            return
        case .none:
            t.resume()
        }
        time_status = .resume
    }
    
    // 挂起
    func suspend() {
        guard let t = timer else {
            return
        }
        
        switch time_status {
        case .suspend:
            return
        case .resume:
            t.suspend()
        case .none:
            return
        }
        time_status = .suspend
    }
    
    // 关闭
    func close() {
        guard let t = timer else {
            return
        }
        
        switch time_status {
        case .suspend:
            t.resume()
        case .resume:
            break
        case .none:
            return
        }
        
        t.cancel()
        t.setEventHandler(handler: nil)
        timer = nil
        time_status = .none
    }
}

private extension BLGCDTimer {
    func createTimer() {
        timer = DispatchSource.makeTimerSource(flags: .strict, queue: self.workQueue)
        guard let t = timer else{
            return
        }
        t.schedule(deadline: self.deadline, repeating: self.repeating, leeway: self.leeway)
        t.setEventHandler(handler: self.handler)
        time_status = .none
    }
}
